//
// Created by denglibin on 19-10-25.
//
/*多进程并发服务器*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <ctype.h>
#include <wait.h>
#include <errno.h>
#include "wrap.h"

static const int port = 8888;

/**
 * 父进程SIGCHLD信号信号处理函数
 * @param signo
 */
void wait_handle_(int signo){
   while ((waitpid(0, NULL, WNOHANG)) > 0); // 循环 回收多个（可能有多个子进程结束但只收到一次信号）
}
/**
 * 通过信号来回收子进程 (会造成accept函数  Interrupted system call 错误)
 */
void wait_child_by_signal(){
    // 设置信号处理函数
    struct sigaction new_act;
    new_act.sa_handler = wait_handle_;
    sigemptyset(& new_act.sa_mask);
    new_act.sa_flags = 0;
    sigaction(SIGCHLD, &new_act, NULL);
}

/**
 *
 *回收子进程
 */
static void wait_child(){
    int child_pit;
    printf("wait child\n");
    while((child_pit = waitpid(0, NULL, WNOHANG)) > 0){
        // 回收子进程
        printf("wait success child_pid = %d\n", child_pit );
    }
    if(child_pit < 0){
        perror("wait:");
    }
}
/**
 * 启动服务
 */
static void start_server(){
    int status = 1;
    int pid;
    int socket_fd = Socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr;
    int client_socket_fd = 0;
    struct sockaddr_in client_addr;
    int  sock_size = sizeof(struct sockaddr_in);
    char buf[1024];
    memset(buf, 0, 1024);
    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);
    Bind(socket_fd, (struct sockaddr*) &addr, sizeof(struct sockaddr));
    Listen(socket_fd, 128);
    printf("wait for connection...\n");

    while (status){
        client_socket_fd = Accept(socket_fd, (struct sockaddr *) &client_addr, &sock_size);
        if(errno == EINTR){
            perror("accept:");
            continue;
        }
        inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, buf, sizeof(buf));
        printf("client ip = %s, port = %d\n", buf, ntohs(client_addr.sin_port));
        pid = fork();
        if(pid == 0){
            // in child 子进程
            Close(socket_fd);
            break;
        }else{
            // in parent
            Close(client_socket_fd);
            client_socket_fd = 0;
            wait_child(); // 回收一下子进程
        }
    }

    if(client_socket_fd != 0){ // 子进程
        while(1){
            bzero(buf, 1024);
            int len = recv(client_socket_fd, buf, sizeof(buf), 0); // 接收数据
            printf("%s", buf);
            if(len <= 0){
                printf("client disconnected\n");
                Close(client_socket_fd);
                break;
            }
            for(int i = 0; i < len; i++){
                buf[i] = toupper(buf[i]);
            }
            Send(client_socket_fd, buf, len, 0); //发送数据
        }
    } else { // 父进程
        wait_child(); //回收一下子进程
    }
}

static int main_(int argc, char * argv[]){
    start_server();
    return 0;
}